package com.gmrz.uaf.servlet.v1.handler;

import com.gmrz.uaf.common.Constants;
import com.gmrz.uaf.common.GuiceUtil;
import com.gmrz.uaf.protocol.v1.json.UAFSchemaBuilder;
import com.gmrz.uaf.protocol.v1.schema.AuthenticationResponse;
import com.gmrz.uaf.remote.protocol.v1.processor.UAPIDAuthFinishProcessor;
import com.gmrz.uaf.server.ServerContext;
import com.gmrz.uaf.servlet.v1.request.IDAuthContext;
import com.gmrz.uaf.servlet.v1.request.ReceiveReqPayload;
import com.gmrz.uaf.servlet.v1.response.FidoRespPayload;
import com.gmrz.uaf.servlet.v1.validation.PayloadValidationException;
import com.gmrz.uaf.servlet.v1.validation.RestValidator;
import com.gmrz.util.Convert;
import com.google.common.base.Strings;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.lang.reflect.Type;
import java.util.List;

/**
 * Created by gongyuqiang on 2017/5/8.
 */
public class UAPIDAuthResponseHandler extends UAFBaseHandler {
    private static final Logger LOG = LogManager.getLogger(UAPIDAuthRequestHandler.class);

    /**
     *  {
     *     "uafResponse":"[{…}]",
     *     "context":{
     *          "transNo":"32characters",
     *          "appID","001",
     *          "userName":"123456",
     *          "authType":"12"
     *     }
     * }
     * @param request
     * @return
     * {
     *     "statusCode":1200,
     *     "description":"OK"
     * }
     */
    public String idauthFinish(String request){
        LOG.info("[/idauth/send][begin]");
        ServerContext.getServerContext().getFidoLog().setRequest(request);
        Gson gson = UAFSchemaBuilder.getGson();
        FidoRespPayload<String> respPayload = new FidoRespPayload<String>();
        Type reqType = new TypeToken<ReceiveReqPayload<IDAuthContext>>() {}.getType();
        String response = null;
        try {
            ReceiveReqPayload<IDAuthContext> reqPayload = gson.fromJson(request, reqType);
            ServerContext.getServerContext().setBase64(reqPayload.getContext().isBase64());
            logRequest(request,reqPayload.getContext().getTransNo(),reqPayload.getContext().getUserName(),
                    reqPayload.getContext().getAppID(), reqPayload.getContext().getAuthType(),reqPayload.getContext().getTransType(), Constants.Method.IDAUTH_FINISH);
            validate(reqPayload);
            UAPIDAuthFinishProcessor processor = GuiceUtil.getProcessorInjector()
                    .getInstance(UAPIDAuthFinishProcessor.class);
            IDAuthContext context = reqPayload.getContext();
            String uafMessage = null;
            if(ServerContext.getServerContext().isBase64()) {
                uafMessage = new String(Convert.fromBase64(reqPayload.getUafResponse()));
            }else {
                uafMessage = reqPayload.getUafResponse();
            }

            Type type = new TypeToken<List<AuthenticationResponse>>() {  } .getType();

            List<AuthenticationResponse> authResponses = gson.fromJson(uafMessage, type);

            AuthenticationResponse authResponse = null;
            if ((authResponses != null) && (!authResponses.isEmpty())) {
                if (authResponses.size() > 1) {
                    authResponse = RestValidator.compareAuthRespVersions(authResponses);
                } else authResponse = authResponses.get(0);
            }


            if (null == authResponse) {
                LOG.error("uafResponse is Null");
                throw new PayloadValidationException("uafResponse", RestValidator.VALIDATION_ERROR.EMPTY);
            }

            processor.process(authResponse, context.getAppID(), context.getAuthType(), context.getUserName(),context.getTransType());

            respPayload.setStatusCode(Constants.StatusCode.OK.getCode());
            respPayload.setDescription("OK");
            response =  gson.toJson(respPayload);
        } catch (Exception ex) {
            LOG.error(ex);
            response = buildFidoRespFromException(respPayload, ex);
        }
        LOG.info("[/idauth/send][end]");
        return response;
    }

    void validate(ReceiveReqPayload<IDAuthContext> payload) throws PayloadValidationException {

        if ((payload == null) || (payload.getContext() == null)) {
            throw new PayloadValidationException("context", RestValidator.VALIDATION_ERROR.EMPTY);
        }
        if ((null == payload) || (Strings.isNullOrEmpty(payload.getUafResponse()))) {
            LOG.error("Payload does not contains UAFRegResponse");
            throw new PayloadValidationException("UAFRegResponse", RestValidator.VALIDATION_ERROR.EMPTY);
        }

        IDAuthContext context = payload.getContext();
        //if(payload.getContext().getAuthType().compareTo(Constants.AuthType.REMOTE_FACEPRINT.getAuthType()) < 0)
        RestValidator.validate("uafResponse", payload.getUafResponse());;
        RestValidator.validate("appID", context.getAppID());
        RestValidator.validate("authType", context.getAuthType());
        RestValidator.validate("userName", context.getUserName());
        RestValidator.validate("transNo", context.getTransNo());
    }
}
